/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.boudreaulocke.model;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Phone number object. Currently supports only US phone numbers.
 * 
 * @author Jonathan Locke
 */
public class PhoneNumber {

	private int areaCode;
	private int prefix;
	private int suffix;

	/**
	 * Strict regular expression pattern for US phone numbers
	 */
	private static final Pattern USA = Pattern
			.compile("\\((\\d\\d\\d)\\) (\\d\\d\\d)-(\\d\\d\\d\\d)");

	/**
	 * @param locale
	 *            The locale (currently must be US)
	 * @param value
	 *            The value to parse in strict "(###) ###-####" format
	 * @return Phone number for value
	 * @throws PhoneNumberParseException
	 *             Thrown if locale is not supported or phone number is not
	 *             formatted right
	 */
	public static PhoneNumber parse(Locale locale, String value)
			throws PhoneNumberParseException {
		if (locale.equals(Locale.US)) {
			Matcher matcher = USA.matcher(value);
			if (matcher.matches()) {
				int areaCode = Integer.parseInt(matcher.group(1));
				int prefix = Integer.parseInt(matcher.group(2));
				int suffix = Integer.parseInt(matcher.group(3));
				return new PhoneNumber(areaCode, prefix, suffix);
			}
			throw new PhoneNumberParseException("Invalid phone number: "
					+ value);
		}
		throw new PhoneNumberParseException("Unsupported locale");
	}

	/**
	 * Construct for Hibernate.
	 */
	public PhoneNumber() {
	}

	/**
	 * Copy construct.
	 * 
	 * @param value
	 *            The value to copy
	 */
	public PhoneNumber(PhoneNumber value) {
		this(value.areaCode, value.prefix, value.suffix);
	}

	/**
	 * @param areaCode
	 *            Area code (000-999)
	 * @param prefix
	 *            Prefix (000-999)
	 * @param suffix
	 *            Suffix (000-9999)
	 */
	public PhoneNumber(int areaCode, int prefix, int suffix) {
		if (areaCode < 0 || areaCode > 999) {
			throw new IllegalArgumentException("Invalid area code: " + areaCode);
		}
		if (prefix < 0 || prefix > 999) {
			throw new IllegalArgumentException("Invalid prefix: " + prefix);
		}
		if (suffix < 0 || suffix > 9999) {
			throw new IllegalArgumentException("Invalid suffix: " + suffix);
		}
		this.areaCode = areaCode;
		this.prefix = prefix;
		this.suffix = suffix;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		return "(" + String.format("%03d", areaCode) + ") "
				+ String.format("%03d", prefix) + "-"
				+ String.format("%04d", suffix);
	}
}
